/**
 * <p>文件名:		RsaUtils.java</p>
 * <p>版权:		CopyrightTag</p>
 * <p>公司:		CompanyTag</p>
 * @author		周华彬(zhouhuabin@chinatransinfo.com, zhou_hua_bin@163.com)
 */

package com.caits.lbs.framework.utils;

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.slf4j.Logger;

import com.caits.lbs.framework.log.CommonSlf4jLogFactory;

/**
 * <p>
 * RsaUtils
 * </p>
 * <p>
 * rsa非对称加密算法，默认采用1024位
 * </p>
 * @author 周华彬(zhouhuabin@chinatransinfo.com, zhou_hua_bin@163.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th>
 *          <th width="100px">动作</th>
 *          <th width="100px">修改人</th>
 *          <th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>zhouhuabin</td>
 *          <td>2015年12月1日 下午2:47:57</td>
 *          </tr>
 *          <tr>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          </tr>
 *          </table>
 */
public class RsaUtils {
	/** 变量:TODO,类型:Logger */
	protected static Logger log = CommonSlf4jLogFactory.getLog();
	/** 指定加密算法为RSA */
	private static String ALGORITHM = "RSA";
	/** 指定key的大小 */
	private static int KEYSIZE = 1024;

	/** RSA算法要求有一个可信任的随机数源 */
	private static SecureRandom sr = new SecureRandom();

	private final static int PRIVATE = 1;
	private final static int PUBLIC = 2;

	/**
	 * 生成密钥对
	 * 
	 * <pre>
	 * // 得到公钥
	 * Key publicKey = kp.getPublic();
	 * // 得到私钥
	 * Key privateKey = kp.getPrivate();
	 * </pre>
	 * @return KeyPair 秘钥公钥对
	 */
	public static KeyPair generateKeyPair() {
		try {
			/** 为RSA算法创建一个KeyPairGenerator对象 */
			KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
			/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
			kpg.initialize(KEYSIZE, sr);
			/** 生成密匙对 */
			KeyPair kp = kpg.generateKeyPair();
			return kp;
		} catch (Exception e) {
			log.error("生成rsa秘钥对错误,msg=" + e.getLocalizedMessage());
		}
		return null;
	}

	/**
	 * 用公钥rsa加密 源数据
	 * @param publicKey 公钥对象数组
	 * @param sourceByte 待加密的数据
	 * @return byte[] 加密后的数据
	 * @throws Exception String
	 */
	public static byte[] encrypt(byte[] publicKey, byte[] sourceByte) throws Exception {
		try {
			RSAPublicKey key = (RSAPublicKey) generateKey(publicKey,2);
			//模  
	        String modulus = key.getModulus().toString();  
	        //公钥指数  
	        String public_exponent = key.getPublicExponent().toString();  
	        //私钥指数  
//	        String private_exponent = key.getPrivateExponent().toString();  
	        log.info("构造出RSAPublicKey对象的module={},exponent={}",modulus,public_exponent);
			/** 得到Cipher对象来实现对源数据的RSA加密 */
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE, key);
			/** 执行加密操作 */
			byte[] rsaByte = cipher.doFinal(sourceByte);
			return rsaByte;
		} catch (Exception e) {
			log.error("加密rsa数据错误,msg=" + e.getLocalizedMessage());
		}
		return null;
	}

	/**
	 * 用公钥rsa加密 源数据
	 * @param publicKey 公钥对象
	 * @param sourceByte 待加密的数据
	 * @return byte[] 加密后的数据
	 * @throws Exception String
	 */
	public static byte[] encrypt(PublicKey publicKey, byte[] sourceByte) throws Exception {
		try {
			/** 得到Cipher对象来实现对源数据的RSA加密 */
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			/** 执行加密操作 */
			byte[] rsaByte = cipher.doFinal(sourceByte);
			return rsaByte;
		} catch (Exception e) {
			log.error("加密rsa数据错误,msg=" + e.getLocalizedMessage());
		}
		return null;
	}

	/**
	 * 用私钥rsa解密收到的数据
	 * @param privateKey 私钥对象
	 * @param rsaByte 待解密的数据
	 * @return byte[] 解密后的数据
	 * @throws Exception String
	 */
	public static byte[] decrypt(byte[] privateKey, byte[] rsaByte) throws Exception {
		try {
			RSAPrivateKey key = (RSAPrivateKey) generateKey(privateKey,1);
			//模  
	        String modulus = key.getModulus().toString();  
	        //公钥指数  
//	        String public_exponent = key.getPublicExponent().toString();  
	        //私钥指数  
	        String private_exponent = key.getPrivateExponent().toString(); 
	        log.info("构造出RSAPrivateKey对象的module={},exponent={}",modulus,private_exponent);
			/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, key);
			/** 执行解密操作 */
			byte[] b = cipher.doFinal(rsaByte);
			return b;
		} catch (Exception e) {
			log.error("解密rsa数据错误,msg=" + e.getLocalizedMessage());
		}
		return null;
	}

	/**
	 * 按类型生成钥匙对象 
	 * @param keyData
	 * @param type
	 * @return Key
	 */
	public static Key generateKey(byte[] keyData, int type) {
		try {
			Key key = null;
			KeyFactory kf = KeyFactory.getInstance(ALGORITHM);
			switch (type) {
			case PRIVATE:
				PKCS8EncodedKeySpec encodedPrivateKey = new PKCS8EncodedKeySpec(keyData);
				key = kf.generatePrivate(encodedPrivateKey);
				return key;
			case PUBLIC:
				X509EncodedKeySpec encodedPublicKey = new X509EncodedKeySpec(keyData);
				key = kf.generatePublic(encodedPublicKey);
				return key;
			}
		} catch (Exception e) {
			log.error("生成rsa.key对象错误,msg=" + e.getLocalizedMessage());
		}
		return null;
	}
	/** 
     * 使用模和指数生成RSA公钥 对象
     * 注意：【此代码用了默认补位方式，为RSA/None/PKCS1Padding，不同JDK默认的补位方式可能不同，如Android默认是RSA 
     * /None/NoPadding】 
     * @param modulus     模 
     * @param exponent   指数 
     * @return 
     */  
    public static RSAPublicKey getPublicKey(String modulus, String exponent) {  
        try {  
            BigInteger b1 = new BigInteger(modulus);  
            BigInteger b2 = new BigInteger(exponent);  
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);  
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);  
        } catch (Exception e) {  
        	log.error("生成RSAPublicKey对象错误,msg=" + e.getLocalizedMessage());
            return null;  
        }  
    }
	/** 
     * 使用模和指数生成RSA私钥 对象
     * 注意：【此代码用了默认补位方式，为RSA/None/PKCS1Padding，不同JDK默认的补位方式可能不同，如Android默认是RSA 
     * /None/NoPadding】 
     * @param modulus     模 
     * @param exponent   指数 
     * @return 
     */  
    public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {  
        try {  
            BigInteger b1 = new BigInteger(modulus);  
            BigInteger b2 = new BigInteger(exponent);  
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);  
            return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);  
        } catch (Exception e) {  
        	log.error("生成RSAPrivateKey对象错误,msg=" + e.getLocalizedMessage());
            return null;  
        }  
    }  
  
	/**
	 * 用私钥rsa解密收到的数据
	 * @param privateKey 私钥对象
	 * @param rsaByte 待解密的数据
	 * @return byte[] 解密后的数据
	 * @throws Exception String
	 */
	public static byte[] decrypt(PrivateKey privateKey, byte[] rsaByte) throws Exception {
		try {
			/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			/** 执行解密操作 */
			byte[] b = cipher.doFinal(rsaByte);
			return b;
		} catch (Exception e) {
			log.error("解密rsa数据错误,msg=" + e.getLocalizedMessage());
		}
		return null;
	}

	/**
	 * FIXME
	 * @param args
	 * @throws Exception void
	 */
	public static void main(String[] args) throws Exception {
		//一次生成，多次使用：可以保存
//		KeyPair pair = generateKeyPair();
		byte[] privateByte = Base64Codec.decode("MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAIKNGJYtCFn++4y3SfgGwDKlKv7F5AU1f0XBZK3EFymXG73coOzts5Jh362xt/LZcN/E+J8su+5ZByb+dq1ICESVD2wb0yax2sZ3oVZ6abDsPTmjPtWeQYg9ioxFAK7W/K+CRQ0aZT2Y2EpSKpft8H8yZZ+23lNtivjS7JoSO6MhAgMBAAECgYByO4XU+iiBnvR7J3JI3ZdVeWLKtVuVFz97SQKQbbGayccTdbc2ObPUFWIEeSotDAiRNKgbl6gFoc75VtV/QDVClLoDKYjfAiAPzqSgEqmfI0NOpQdInw8tqwOsfUF8oX/FI52RfNBx96e5x69ZiiszYxbO5B74yfBjLVwGlJT2sQJBAMQEgpav/wQO1ebovgir/7cfhikhPeOO3M23QoqScZLHcw19b4sWJIinJEHxMIZbTX7iQSyPmvodHL4aXa7SEs0CQQCqgB7Wj1Mlm1MlMJTN/+pIa/apbpsySl1bYdiEKMtrluNKc5E+7T92w1PFQ+A+c2OArIQX72ND6UyKUp9P/ZmlAkEAhp3SUUptCIxnujz8xVfaNhkgOf7qUe07FsxUlnYcKYFwMkOC5zI9xNuEuwS5Hox1nD4mJEQ7WqnDo4rX68e5wQJBAJLcxzNjw2gaUdUv8o06yhBVxuMM3evEuIOVVY4JIadsEh44S70bWNYwy8CYhdjlRak5cJK5ZhTCKWbgYk/hju0CQQCdD3brbd2XzgtdiHHWClWtq2+1kR5VXdS8/wpurdae5zN4ZR+4jHDV7fNayz1QwFypD9GU2Nek5LOR+ED2ePmJ".toCharArray());//pair.getPrivate().getEncoded();
		byte[] publicByte = Base64Codec.decode("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCjRiWLQhZ/vuMt0n4BsAypSr+xeQFNX9FwWStxBcplxu93KDs7bOSYd+tsbfy2XDfxPifLLvuWQcm/natSAhElQ9sG9MmsdrGd6FWemmw7D05oz7VnkGIPYqMRQCu1vyvgkUNGmU9mNhKUiqX7fB/MmWftt5TbYr40uyaEjujIQIDAQAB".toCharArray());//pair.getPublic().getEncoded();
		String privateKey = new String(Base64Codec.encode(privateByte));
		String publicKey = new String(Base64Codec.encode(publicByte));
		log.info("get private rsa base64str:" + privateKey);
		log.info("get public rsa base64str:" + publicKey);
		String source = "Hello World!hehehe,are you ready?";// rsa要加密的字符串
		String modulus="91676139699376204268121729209384110929420375075275530599023594247314385475140276777572313086288042826771411965860115063035744057328551448281589868118411431731101463422459506528617814629992872323118535850520184454661764729088352190753390918208606116016144178308891740879813727986648505594099995361640521114401";
		String public_exponent="65537";
		String private_exponent="80216797092645809752589232975450994724317735152534832265758396205383881396339764893264633625786774126084602883596263153482532660443807052530750125688546965100921500626725874742481733430394358489289607878544400185542263455046198819542176319216687909155534379734378547170313492925474804873359278815319080367793";
		RSAPrivateKey privateK = getPrivateKey(modulus, private_exponent);
		RSAPublicKey publicK = getPublicKey(modulus, public_exponent);
		byte[] cryptosByte = encrypt(publicByte, source.getBytes());// 生成的密文rsa
		log.info(new String(Base64Codec.encode(cryptosByte)));
		// 经测试，rsa加密后数据长度至少翻倍，私钥长度640，公钥长度160，modulus长度300，公钥exponent5位，私钥exponent300位
		byte[] target = decrypt(privateByte, cryptosByte);// 解密密文
		log.info(new String(target));

	}
}
